﻿using System.Net;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.Loader;

namespace Lib.Assemblys;
/// <summary>
/// 程序集加载器
/// </summary>
public static class AssemblyLoader {
    /// <summary>
    /// 静态构造函数
    /// </summary>
    static AssemblyLoader() {
       Ins = []; Assemblys = [];
    }
    /// <summary>
    /// 类的类型列表（集合）
    /// </summary>
    public static Dictionary<string, Type> Ins { get; internal set; }
    /// <summary>
    /// 程序集信息列表（集合）
    /// </summary>
    public static Dictionary<string, Assembly> Assemblys { get; internal set; }
    /// <summary>
    /// 动态加载程序集并返回指定类的类型
    /// </summary>
    public static Type LoadAssemblyFile(string Path, string ClassName) {
        if (Ins.TryGetValue(ClassName, out Type Value)) {
            return Value;
        }
        Path = Path.Replace(@"\","/");
        if (Path.Contains(":/") || Path.StartsWith('/')) {

        } else {
            Path = System.IO.Path.Combine(Directory.GetCurrentDirectory(), Path).Replace(@"\", "/");
        }
        if (System.IO.File.Exists(Path)) {
            var File = System.IO.Path.GetFileName(Path);
            try {
                AssemblyLoadContext Context;
                Assembly Assembly;
                if (Assemblys.TryGetValue(Path, out Assembly _Assembly)) {
                    Assembly = _Assembly;
                } else {
                    Context = new AssemblyLoadContext(Path);
                    Assembly = Context.LoadFromAssemblyPath(Path);
                    if (Assembly == null) {
                        return null;
                    }
                    Assemblys.Add(Path, Assembly);
                    Context.Resolving += (Context, AssemblyName) => {
                        var Path = System.IO.Path.Combine(Directory.GetParent(Context.Name).FullName, $"{AssemblyName.Name}.DLL").Replace(@"\", "/");
                        if (System.IO.File.Exists(Path)) {
                            try {
                                var Assembly = Context.LoadFromAssemblyPath(Path);
                                if (Assembly == null) {
                                    return null;
                                }
                                Console.WriteLine($"\n加载依赖项 {Path} 成功");
                                return Assembly;
                            } catch (Exception ex) {
                                Console.WriteLine($"\n加载依赖项 {Path} 失败");
                                Console.WriteLine($"\n依赖项信息 {ex.Message}");
                            }
                        } else {
                            Console.WriteLine($"\n依赖项文件不存在 {Path}");
                        }
                        return null;
                    };
                }
                var Type = Assembly.GetType(ClassName);
                if (Type == null) {
                    return null;
                }
                Ins.Add(ClassName, Type);
                Console.WriteLine($"\n程序集路径 {Path}");
                Console.WriteLine($"\n加载程序集 {File},{ClassName} 成功");
                return Type;
            } catch (Exception ex) {
                Console.WriteLine($"\n程序集路径 {Path}");
                Console.WriteLine($"\n加载程序集 {File} 失败");
                Console.WriteLine($"\n程序集信息 {ex.Message}");
            }
        } else {
            Console.WriteLine($"\n程序集文件不存在 {Path}");
        }
        return null;
    }

    #region "反射调用"

    /// <summary>
    /// 获取程序集（Assembly）
    /// </summary>
    /// <param name="AssemblyName">程序集名称</param>
    /// <returns></returns>
    public static Assembly LoadAssemblyName(string AssemblyName) {
        if (Assemblys.TryGetValue(AssemblyName, out Assembly Value)) {
            return Value;
        }
        Assembly Assembly;
        try {
            Assembly = System.Reflection.Assembly.Load(AssemblyName);
            if (Assemblys.TryGetValue(Assembly.Location.Replace(@"\", "/"), out Assembly _Assembly)) {
                Assembly = _Assembly;
            }
        } catch {
            try {
                Assembly = System.Reflection.Assembly.LoadFrom($"{AssemblyName}.DLL");
                if (Assemblys.TryGetValue(Assembly.Location.Replace(@"\", "/"), out Assembly _Assembly)) {
                    Assembly = _Assembly;
                }
            } catch {
                Assembly = null;
            }
        }
        if(Assembly != null) {
            Assemblys.Add(AssemblyName, Assembly);
        }
        return Assembly;
    }
    /// <summary>
    /// 获取指定程序集名称与类名的类型
    /// </summary>
    /// <param name="AssemblyName">程序集名称</param>
    /// <param name="ClassName">类名全称</param>
    /// <returns></returns>
    public static Type GetType(string AssemblyName, string ClassName) {
        var Key = ClassName;
        if (Ins.TryGetValue(Key, out Type Value)) {
            return Value;
        }
        Assembly Assembly = LoadAssemblyName(AssemblyName);
        if (Assembly != null) {
            Type Type = Assembly.GetType(Key);
            if (Type != null) {
                Ins.Add(Key, Type);
            }
            return Type;
        }
        return null;
    }
    /// <summary>
    /// 调用静态类、非静态类的方法(静态方法、实例方法)
    /// </summary>
    /// <param name="T">类的类型（静态类、非静态类）</param>
    /// <param name="InvokeName">方法名称，为空时,调用的是类的构造方法</param>
    /// <param name="Args">参数数组</param>
    public static object Invoke(this Type T, string InvokeName = null, params object[] Args) {
        if (T != null) {
            bool IsParameters = false;
            if (Args != null && Args.Length > 0) {
                IsParameters = true;
            }
            if (string.IsNullOrEmpty(InvokeName)) {
                if (!T.IsAbstract) {
                    if (IsParameters) {
                        return Activator.CreateInstance(T, Args);
                    } else {
                        return Activator.CreateInstance(T);
                    }
                }
            } else {
                object That = null;
                if (!T.IsAbstract) {
                    That = Activator.CreateInstance(T);
                }
                Type[] TKeys = [];
                if (IsParameters) {
                    TKeys = new Type[Args.Length];
                    int i = 0;
                    foreach (var o in Args) {
                        if (o != null) {
                            TKeys[i] = o.GetType();
                        } else {
                            TKeys[i] = typeof(object);
                        }
                        i++;
                    }
                } else {
                    Args = null;
                }
                var M = T.GetMethod(InvokeName, TKeys);
                if (M != null) {
                    return M.Invoke(That, Args);
                }
            }
        }
        return null;
    }
    /// <summary>
    /// 调用静态类、非静态类的方法(静态方法、实例方法)
    /// </summary>
    /// <param name="e">类的实例（静态类、非静态类）</param>
    /// <param name="InvokeName">方法名称</param>
    /// <param name="Args">参数数组</param>
    /// <returns></returns>
    public static object Invoke(this object e, string InvokeName, params object[] Args) {
        if (e != null) {
            if (!string.IsNullOrEmpty(InvokeName)) {
                Type T = e.GetType();
                Type[] TKeys = [];
                if (Args != null && Args.Length > 0) {
                    TKeys = new Type[Args.Length];
                    int i = 0;
                    foreach (object o in Args) {
                        TKeys[i] = o.GetType(); i++;
                    }
                } else {
                    Args = null;
                }
                return T.GetMethod(InvokeName, TKeys).Invoke(e, Args);
            }
        }
        return null;
    }
    /// <summary>
    /// 获取静态类、非静态类的属性值
    /// </summary>
    /// <param name="e">类的类型（静态类、非静态类）</param>
    /// <param name="Name">属性名称</param>
    /// <returns></returns>
    public static object GetAttribute(this Type e, string Name) {
        if (e != null) {
            object That = null;
            if (!e.IsAbstract) {
                That = Activator.CreateInstance(e);
            }
            return e.GetProperty(Name).GetValue(That, null);

        }
        return null;
    }
    /// <summary>
    /// 获取静态类、非静态类的属性值
    /// </summary>
    /// <param name="e">类的实例（静态类、非静态类）</param>
    /// <param name="Name">属性名称</param>
    /// <returns></returns>
    public static object GetAttribute(this object e, string Name) {
        if (e != null) {
            Type Type = e.GetType();
            if (!Type.IsValueType && Type.Name != "String") {
                return Type.GetProperty(Name)?.GetValue(e, null);
            }
        }
        return null;
    }
    /// <summary>
    /// 获取嵌入式资源文本内容
    /// </summary>
    /// <param name="AssemblyName">程序集名称</param>
    /// <param name="ResourceName">资源名称</param>
    /// <returns>资源内容</returns>
    public static string GetAssemblyResource(string AssemblyName, string ResourceName) {
        return GetAssemblyResource(Assembly.Load(AssemblyName), ResourceName);
    }
    /// <summary>
    /// 获取嵌入式资源文本内容
    /// </summary>
    /// <param name="ResourceType">与指定的类型</param>
    /// <param name="ResourceName"></param>
    /// <returns></returns>
    public static string GetAssemblyResource(Type ResourceType, string ResourceName) {
        return GetAssemblyResource(ResourceType.Assembly, ResourceName);
    }
    /// <summary>
    /// 获取嵌入式资源文本内容
    /// </summary>
    /// <param name="Assembly">程序集</param>
    /// <param name="ResourceName">资源的名称</param>
    /// <returns>嵌入式资源文本内容</returns>
    public static string GetAssemblyResource(Assembly Assembly, string ResourceName) {
        using var Stream = Assembly.GetManifestResourceStream(ResourceName);
        if (Stream == null) {
            return null;
        }
        var Reader = new StreamReader(Stream);
        var Result = Reader.ReadToEnd();
        Reader.Close();
        return Result;
    }
    /// <summary>
    /// 
    /// </summary>
    public static void Clear() {
        Ins.Clear();
    }

    #endregion

}

